package com.greateamd.timetableasy.server.dao.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.greateamd.timetableasy.client.domain.AuthType;
import com.greateamd.timetableasy.domain.Auth;
import com.greateamd.timetableasy.domain.Event;
import com.greateamd.timetableasy.domain.Room;
import com.greateamd.timetableasy.domain.User;
import com.greateamd.timetableasy.domain.exceptions.DBServerSideException;
import com.greateamd.timetableasy.server.dao.RoomDAO;
import com.greateamd.timetableasy.server.dao.util.AbstractHibernateDAO;



@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, readOnly = false)	
@Repository("roomDAO")
public class RoomDAOImpl extends AbstractHibernateDAO<Room,Integer> implements RoomDAO {

	public RoomDAOImpl() {
		super(new Room());
	}

	@Override
	public boolean getDisponibility(final Integer excluseThisEventId,final String room,final Date from, final int duration) throws HibernateException,SQLException {
		return getHibernateTemplate().execute(new HibernateCallback<Boolean>() {

			public Boolean doInHibernate(Session session) throws HibernateException,SQLException {
				//get campus events
				String hql = "SELECT distinct(event) " +
				 "FROM Event event " +
			 	 "WHERE event.location LIKE :location " +
			 	 	"AND day(event.startDate) = day(:from) ";
				if(excluseThisEventId != null){
					hql += " AND event.id != :excludeEventId";
				}
				final Query query = session.createQuery(hql);
				query.setParameter("location", room );
				query.setDate("from", from);
				if(excluseThisEventId != null){
					query.setParameter("excludeEventId", excluseThisEventId );
				}
				final List<Event> list = query.list();
				
				for(Event event : list){
					final int startHour = event.getStartDate().getHours();
					final int endHour = startHour+event.getDuration();
					final int startHourRequest = from.getHours();
					final int endHourRequest = startHourRequest+duration;
					if( startHourRequest <= startHour && startHour < endHourRequest ){
						return false;
					} else if( startHourRequest < endHour && endHour <= endHourRequest ){
						return false;
					}
				}
				return true;
	        }
	    });
	}

	@Override
	public List<Room> getAllOfLoggedUser() throws DBServerSideException, HibernateException, SQLException {
		final User loggedUser = getHibernateTemplate().execute(new HibernateCallback<User>() {
			@Override
			public User doInHibernate(Session session) throws HibernateException, SQLException {
				final String username = SecurityContextHolder.getContext().getAuthentication().getName();
				return (User) session.get(User.class, username);
			}});
		
		if(loggedUser.getAuths().contains(new Auth(loggedUser,AuthType.ROLE_ADMIN))){
			return getAll();
		} else if(loggedUser.getAuths().contains(new Auth(loggedUser,AuthType.ROLE_CAMPUS_MANAGER))){
			logger.debug("Get all campus manager from db");
			return (List<Room>) getHibernateTemplate().execute(new HibernateCallback<List<Room>>() {

				public List<Room> doInHibernate(Session session) throws HibernateException,SQLException {
					//get Room of this campus manager
					String hql = "SELECT distinct(room) " +
					 "FROM Room room " +
					 "JOIN room.campus campus JOIN campus.managers user " +
					 	"WITH user.username = :username "+
					 "ORDER BY room.campus";
					Query query = session.createQuery(hql);
					query.setParameter("username", loggedUser.getUsername());
					List<Room> list = query.list();
					return list;
		        }
		    });
		} else {
			return new ArrayList<Room>();
		}
	}
}